#include <stdlib.h>
#include <string.h>
#include "image.h"

Image::~Image()
{
    Resize(0, 0);
}

Image::Image()
{
    memset(&info, 0, sizeof(info));
    Resize(0, 0);
}

Image::Image(int32_t width, int32_t height, ImageFormat format, uint8_t* mem)
{
    memset(&info, 0, sizeof(info));
    Resize(width, height, format, mem);
}

Image::Image(const Image& obj)
{
    memset(&info, 0, sizeof(info));
    Resize(obj.Width(), obj.Height(), obj.Format());
    memcpy(info.mem.addr, obj.Mem().addr, obj.Size());
}

void Image::Resize(int32_t width, int32_t height, ImageFormat format, uint8_t* mem)
{
    info.width = width;
    info.height = height;
    info.pb = format > IMAGE_FORMAT_BGR ? 4 : 3;
    info.size = width * height * info.pb;
    info.format = format;
    if (info.mem.addr)
    {
        free(info.mem.addr);
        info.mem.addr = NULL;
    }
    if (mem)
        info.mem.addr = mem;
    else if (info.size > 0)
        info.mem.addr = (uint8_t*)calloc(info.size, 1);
}

int32_t Image::Width() const
{
    return info.width;
}

int32_t Image::Height() const
{
    return info.height;
}

int32_t Image::Pb() const
{
    return info.pb;
}

int32_t Image::Size() const
{
    return info.size;
}

ImageFormat Image::Format() const
{
    return info.format;
}

ImageMem Image::Mem(int32_t x, int32_t y) const
{
    ImageMem retMem = info.mem;
    if (retMem.addr)
        retMem.addr += (y * info.width + x) * info.pb;
    return retMem;
}

ImageInfo Image::Info() const
{
    return info;
}

void Image::ForceSet(uint8_t* addr)
{
    info.mem.addr = addr;
}

void Image::Translate(int32_t width, int32_t height, ImageFormat format, Image& retImg)
{
    retImg.Resize(width, height, format);
    retImg.Write(0, 0, width, height, *this);
}

void Image::Clear(uint32_t color, int32_t x, int32_t y, int32_t width, int32_t height)
{
    if (!info.mem.addr || x >= info.width || y >= info.height)
        return;

    /* 范围检查 */
    width = x + width;
    height = y + height;
    if (width < 1 || height < 1)
        return;
    if (width > info.width)
        width = info.width;
    if (height > info.height)
        height = info.height;

    x = x < 0 ? 0 : x;
    y = y < 0 ? 0 : y;
    
    ImagePointBGRA bgra = {
        (uint8_t)(color & 0xFF),
        (uint8_t)((color >> 8) & 0xFF),
        (uint8_t)((color >> 16) & 0xFF),
        (uint8_t)((color >> 24) & 0xFF)};

    ImageMem tMem = info.mem;

    switch (info.format)
    {
    case IMAGE_FORMAT_RGB:
        {
            ImagePointRGB rgb = {bgra.r, bgra.g, bgra.b};
            for (int32_t cY = y; cY < height; cY++)
            {
                tMem.rgb = info.mem.rgb + (cY * info.width + x);
                for (int32_t cX = x; cX < width; cX++)
                    *tMem.rgb++ = rgb;
            }
        }
        break;
    case IMAGE_FORMAT_BGR:
        {
            ImagePointBGR bgr = {bgra.b, bgra.g, bgra.r};
            for (int32_t cY = y; cY < height; cY++)
            {
                tMem.bgr = info.mem.bgr + (cY * info.width + x);
                for (int32_t cX = x; cX < width; cX++)
                    *tMem.bgr++ = bgr;
            }
        }
        break;
    case IMAGE_FORMAT_RGBA:
        {
            ImagePointRGBA rgba = {bgra.r, bgra.g, bgra.b, bgra.a};
            for (int32_t cY = y; cY < height; cY++)
            {
                tMem.rgba = info.mem.rgba + (cY * info.width + x);
                for (int32_t cX = x; cX < width; cX++)
                    *tMem.rgba++ = rgba;
            }
        }
        break;
    case IMAGE_FORMAT_BGRA:
        {
            for (int32_t cY = y; cY < height; cY++)
            {
                tMem.bgra = info.mem.bgra + (cY * info.width + x);
                for (int32_t cX = x; cX < width; cX++)
                    *tMem.bgra++ = bgra;
            }
        }
        break;
    case IMAGE_FORMAT_ARGB:
        {
            ImagePointARGB argb = {bgra.a, bgra.r, bgra.g, bgra.b};
            for (int32_t cY = y; cY < height; cY++)
            {
                tMem.argb = info.mem.argb + (cY * info.width + x);
                for (int32_t cX = x; cX < width; cX++)
                    *tMem.argb++ = argb;
            }
        }
        break;
    case IMAGE_FORMAT_ABGR:
        {
            ImagePointABGR abgr = {bgra.a, bgra.b, bgra.g, bgra.r};
            for (int32_t cY = y; cY < height; cY++)
            {
                tMem.abgr = info.mem.abgr + (cY * info.width + x);
                for (int32_t cX = x; cX < width; cX++)
                    *tMem.abgr++ = abgr;
            }
        }
        break;
    }
}

void Image::Clear(uint32_t color)
{
    Clear(color, 0, 0, info.width, info.height);
}

#define IMAGE_WRITE(format, array, r, g, b, a) \
if (a != 0xFF) {\
    switch (format) { \
    case IMAGE_FORMAT_RGB:\
    case IMAGE_FORMAT_RGBA:\
        if (!a) {\
            array[0] = r; array[1] = g; array[2] = b;\
        } else {\
            array[0] = (uint8_t)(((uint16_t)array[0] * a + (uint16_t)r * (0xFF - a)) >> 8);\
            array[1] = (uint8_t)(((uint16_t)array[1] * a + (uint16_t)g * (0xFF - a)) >> 8);\
            array[2] = (uint8_t)(((uint16_t)array[2] * a + (uint16_t)b * (0xFF - a)) >> 8);\
            if (format == IMAGE_FORMAT_RGBA && a < array[3]) array[3] = a;\
        } break;\
    case IMAGE_FORMAT_BGR:\
    case IMAGE_FORMAT_BGRA:\
        if (!a) {\
            array[0] = b; array[1] = g; array[2] = r;\
        } else {\
            array[0] = (uint8_t)(((uint16_t)array[0] * a + (uint16_t)b * (0xFF - a)) >> 8);\
            array[1] = (uint8_t)(((uint16_t)array[1] * a + (uint16_t)g * (0xFF - a)) >> 8);\
            array[2] = (uint8_t)(((uint16_t)array[2] * a + (uint16_t)r * (0xFF - a)) >> 8);\
        } if (format == IMAGE_FORMAT_BGRA && a < array[3]) array[3] = a;\
        break;\
    case IMAGE_FORMAT_ARGB:\
        if (!a) {\
            array[1] = r; array[2] = g; array[3] = b;\
        } else {\
            array[1] = (uint8_t)(((uint16_t)array[1] * a + (uint16_t)r * (0xFF - a)) >> 8);\
            array[2] = (uint8_t)(((uint16_t)array[2] * a + (uint16_t)g * (0xFF - a)) >> 8);\
            array[3] = (uint8_t)(((uint16_t)array[3] * a + (uint16_t)b * (0xFF - a)) >> 8);\
        } if (a < array[0]) array[0] = a;\
        break;\
    case IMAGE_FORMAT_ABGR:\
        if (!a) {\
            array[1] = b; array[2] = g; array[3] = r;\
        } else {\
            array[1] = (uint8_t)(((uint16_t)array[1] * a + (uint16_t)b * (0xFF - a)) >> 8);\
            array[2] = (uint8_t)(((uint16_t)array[2] * a + (uint16_t)g * (0xFF - a)) >> 8);\
            array[3] = (uint8_t)(((uint16_t)array[3] * a + (uint16_t)r * (0xFF - a)) >> 8);\
        } if (a < array[0]) array[0] = a;\
        break;\
    }\
}

void Image::Write(int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
    if (x < 0 || x >= info.width || y < 0 || y >= info.height)
        return;
    uint8_t *ptr = info.mem.addr + (y * info.width + x) * info.pb;
    IMAGE_WRITE(info.format, ptr, r, g, b, a);
}

void Image::Write(int32_t x, int32_t y, uint32_t color)
{
    Write(x, y,
        (uint8_t)((color >> 16) & 0xFF),
        (uint8_t)((color >> 8) & 0xFF),
        (uint8_t)(color & 0xFF),
        (uint8_t)((color >> 24) & 0xFF));
}

void Image::Write(int32_t x, int32_t y, int32_t width, int32_t height, Image& plane)
{
    if (!info.mem.addr || !plane.Mem().addr)
        return;

    if (x < width &&
        y < height &&
        x + width > 0 &&
        y + height > 0)
        ;
    else
        return;

    /* image中的理论xy起始位置 */
    int32_t xBegin = x < 0 ? 0 : x;
    int32_t yBegin = y < 0 ? 0 : y;

    int32_t xEnd = x + width;
    int32_t yEnd = y + height;

    /* image中的绘制矩形宽高 */
    int32_t xSize = xEnd > info.width ? info.width - xBegin : xEnd - xBegin;
    int32_t ySize = yEnd > info.height ? info.height - yBegin : yEnd - yBegin;

    /* plane和image的行字节数 */
    int32_t plaLineSize = plane.Width() * plane.Pb();
    int32_t imgLineSize = info.width * info.pb;

    /* plane缩放计数分度格 */
    float xDiv = (float)plane.Width() / width; /* olorImage横/纵向index每次增加量 */
    float yDiv = (float)plane.Height() / height;

    /* plane和image的起始拷贝指针位置 */
    uint8_t *plaPtr = plane.Mem().addr + ((int32_t)((yBegin - y) * yDiv) * plane.Width() + (int32_t)((xBegin - x) * xDiv)) * plane.Pb();
    uint8_t *imgPtr = info.mem.addr + (yBegin * info.width + xBegin) * info.pb;

    /* x/yStep用于plane的xy坐标计数,每次增加x/yDiv */
    float xStep, yStep;
    /* x/yC用于image的xy坐标计数 */
    int32_t xC, yC;

    int32_t xStepInt, yStepInt;

    for (yC = 0, yStep = 0; yC < ySize; yC++)
    {
        uint8_t *pPla = plaPtr;
        uint8_t *pImg = imgPtr;
        for (xC = 0, xStep = 0; xC < xSize; xC++)
        {            
            switch (plane.Format())
            {
            case IMAGE_FORMAT_RGB:
                IMAGE_WRITE(info.format, pImg, pPla[0], pPla[1], pPla[2], 0)
                break;
            case IMAGE_FORMAT_BGR:
                IMAGE_WRITE(info.format, pImg, pPla[2], pPla[1], pPla[0], 0)
                break;
            case IMAGE_FORMAT_RGBA:
                IMAGE_WRITE(info.format, pImg, pPla[0], pPla[1], pPla[2], pPla[3])
                break;
            case IMAGE_FORMAT_BGRA:
                IMAGE_WRITE(info.format, pImg, pPla[2], pPla[1], pPla[0], pPla[3])
                break;
            case IMAGE_FORMAT_ARGB:
                IMAGE_WRITE(info.format, pImg, pPla[1], pPla[2], pPla[3], pPla[0])
                break;
            case IMAGE_FORMAT_ABGR:
                IMAGE_WRITE(info.format, pImg, pPla[3], pPla[2], pPla[1], pPla[0])
                break;
            }

            xStep += xDiv;
            /* 不满1,重复使用plane的该点 */
            if (xStep < 1.0f)
                ;
            /* 大于等于1,移动plane坐标 */
            else
            {
                xStepInt = (int32_t)xStep;
                xStep -= xStepInt;
                pPla += xStepInt * plane.Pb();
            }
            pImg += info.pb;
        }

        yStep += yDiv;
        /* 不满1,重复使用plane的该行 */
        if (yStep < 1.0f)
            ;
        /* 大于等于1,移动plane行 */
        else
        {
            yStepInt = (int32_t)yStep;
            yStep -= yStepInt;
            plaPtr += plaLineSize * yStepInt;
        }
        imgPtr += imgLineSize;
    }
}

void Image::Write(int32_t x, int32_t y, int32_t width, int32_t height, ImageGrid& plane)
{
    ;
}

#define IMAGE_COVER(format, array, r, g, b, a) \
switch (format) { \
case IMAGE_FORMAT_RGB: array[0] = r; array[1] = g; array[2] = b; break; \
case IMAGE_FORMAT_BGR: array[0] = b; array[1] = g; array[2] = r; break; \
case IMAGE_FORMAT_RGBA: array[0] = r; array[1] = g; array[2] = b; array[3] = a; break; \
case IMAGE_FORMAT_BGRA: array[0] = b; array[1] = g; array[2] = r; array[3] = a; break; \
case IMAGE_FORMAT_ARGB: array[0] = a; array[1] = r; array[2] = g; array[3] = b; break; \
case IMAGE_FORMAT_ABGR: array[0] = a; array[1] = b; array[2] = g; array[3] = r; break;}

void Image::Cover(int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
    uint8_t *ptr = info.mem.addr + (y * info.width + x) * info.pb;
    IMAGE_COVER(info.format, ptr, r, g, b, a);
}

void Image::Cover(int32_t x, int32_t y, uint32_t color)
{
    Cover(x, y,
        (uint8_t)((color >> 16) & 0xFF),
        (uint8_t)((color >> 8) & 0xFF),
        (uint8_t)(color & 0xFF),
        (uint8_t)((color >> 24) & 0xFF));
}

void Image::Cover(int32_t x, int32_t y, int32_t width, int32_t height, Image& plane)
{
    if (!info.mem.addr || !plane.Mem().addr)
        return;

    if (x < info.width && y < info.height &&
        x + width > 0 && y + height > 0)
        ;
    else
        return;

    /* image中的理论xy起始位置 */
    int32_t xBegin = x < 0 ? 0 : x;
    int32_t yBegin = y < 0 ? 0 : y;

    int32_t xEnd = x + width;
    int32_t yEnd = y + height;

    /* image中的绘制矩形宽高 */
    int32_t xSize = xEnd > info.width ? info.width - xBegin : xEnd - xBegin;
    int32_t ySize = yEnd > info.height ? info.height - yBegin : yEnd - yBegin;

    /* plane和image的行字节数 */
    int32_t plaLineSize = plane.Width() * plane.Pb();
    int32_t imgLineSize = info.width * info.pb;

    /* plane缩放计数分度格 */
    float xDiv = (float)plane.Width() / width; /*  olorImage横/纵向index每次增加量 */
    float yDiv = (float)plane.Height() / height;

    /* plane和image的起始拷贝指针位置 */
    uint8_t *plaPtr = plane.Mem().addr + ((int32_t)((yBegin - y) * yDiv) * plane.Width() + (int32_t)((xBegin - x) * xDiv)) * plane.Pb();
    uint8_t *imgPtr = info.mem.addr + (yBegin * info.width + xBegin) * info.pb;

    /* x/yStep用于plane的xy坐标计数,每次增加一个Div值 */
    float xStep, yStep;
    /* x/yC用于image的xy坐标计数 */
    int32_t xC, yC;

    int32_t xStepInt, yStepInt;

    for (yC = 0, yStep = 0; yC < ySize; yC++)
    {
        uint8_t *pPla = plaPtr;
        uint8_t *pImg = imgPtr;
        for (xC = 0, xStep = 0; xC < xSize; xC++)
        {            
            switch (plane.Format())
            {
            case IMAGE_FORMAT_RGB:
                IMAGE_COVER(info.format, pImg, pPla[0], pPla[1], pPla[2], 0)
                break;
            case IMAGE_FORMAT_BGR:
                IMAGE_COVER(info.format, pImg, pPla[2], pPla[1], pPla[0], 0)
                break;
            case IMAGE_FORMAT_RGBA:
                IMAGE_COVER(info.format, pImg, pPla[0], pPla[1], pPla[2], pPla[3])
                break;
            case IMAGE_FORMAT_BGRA:
                IMAGE_COVER(info.format, pImg, pPla[2], pPla[1], pPla[0], pPla[3])
                break;
            case IMAGE_FORMAT_ARGB:
                IMAGE_COVER(info.format, pImg, pPla[1], pPla[2], pPla[3], pPla[0])
                break;
            case IMAGE_FORMAT_ABGR:
                IMAGE_COVER(info.format, pImg, pPla[3], pPla[2], pPla[1], pPla[0])
                break;
            }

            xStep += xDiv;
            /* 不满1,重复使用plane的该点 */
            if (xStep < 1.0f)
                ;
            /* 大于等于1,移动plane坐标 */
            else
            {
                xStepInt = (int32_t)xStep;
                xStep -= xStepInt;
                pPla += xStepInt * plane.Pb();
            }
            pImg += info.pb;
        }

        yStep += yDiv;
        /* 不满1,重复使用plane的该行 */
        if (yStep < 1.0f)
            ;
        /* 大于等于1,移动plane行 */
        else
        {
            yStepInt = (int32_t)yStep;
            yStep -= yStepInt;
            plaPtr += plaLineSize * yStepInt;
        }
        imgPtr += imgLineSize;
    }
}

void Image::Cover(int32_t x, int32_t y, int32_t width, int32_t height, ImageGrid& plane)
{
    if (!info.mem.addr || !plane.Mem().addr)
        return;

    if (x < info.width && y < info.height &&
        x + width > 0 && y + height > 0)
        ;
    else
        return;

    /* image中的理论xy起始位置 */
    int32_t xBegin = x < 0 ? 0 : x;
    int32_t yBegin = y < 0 ? 0 : y;

    int32_t xEnd = x + width;
    int32_t yEnd = y + height;

    /* image中的绘制矩形宽高 */
    int32_t xSize = xEnd > info.width ? info.width - xBegin : xEnd - xBegin;
    int32_t ySize = yEnd > info.height ? info.height - yBegin : yEnd - yBegin;

    /* plane和image的行字节数 */
    int32_t plaLineSize = plane.ShadowInfo().width * plane.ShadowInfo().pb;
    int32_t imgLineSize = info.width * info.pb;

    /* plane缩放计数分度格 */
    float xDiv = (float)plane.Width() / width; /*  olorImage横/纵向index每次增加量 */
    float yDiv = (float)plane.Height() / height;

    /* plane和image的起始拷贝指针位置 */
    uint8_t *plaPtr = plane.Mem().addr + (int32_t)((yBegin - y) * yDiv) * plaLineSize + (int32_t)((xBegin - x) * xDiv) * plane.Pb();
    uint8_t *imgPtr = info.mem.addr + yBegin * imgLineSize + xBegin * info.pb;

    /* x/yStep用于plane的xy坐标计数,每次增加一个Div值 */
    float xStep, yStep;
    /* x/yC用于image的xy坐标计数 */
    int32_t xC, yC;

    int32_t xStepInt, yStepInt;

    for (yC = 0, yStep = 0; yC < ySize; yC++)
    {
        uint8_t *pPla = plaPtr;
        uint8_t *pImg = imgPtr;
        for (xC = 0, xStep = 0; xC < xSize; xC++)
        {            
            switch (plane.Format())
            {
            case IMAGE_FORMAT_RGB:
                IMAGE_COVER(info.format, pImg, pPla[0], pPla[1], pPla[2], 0)
                break;
            case IMAGE_FORMAT_BGR:
                IMAGE_COVER(info.format, pImg, pPla[2], pPla[1], pPla[0], 0)
                break;
            case IMAGE_FORMAT_RGBA:
                IMAGE_COVER(info.format, pImg, pPla[0], pPla[1], pPla[2], pPla[3])
                break;
            case IMAGE_FORMAT_BGRA:
                IMAGE_COVER(info.format, pImg, pPla[2], pPla[1], pPla[0], pPla[3])
                break;
            case IMAGE_FORMAT_ARGB:
                IMAGE_COVER(info.format, pImg, pPla[1], pPla[2], pPla[3], pPla[0])
                break;
            case IMAGE_FORMAT_ABGR:
                IMAGE_COVER(info.format, pImg, pPla[3], pPla[2], pPla[1], pPla[0])
                break;
            }

            xStep += xDiv;
            /* 不满1,重复使用plane的该点 */
            if (xStep < 1.0f)
                ;
            /* 大于等于1,移动plane坐标 */
            else
            {
                xStepInt = (int32_t)xStep;
                xStep -= xStepInt;
                pPla += xStepInt * plane.Pb();
            }
            pImg += info.pb;
        }

        yStep += yDiv;
        /* 不满1,重复使用plane的该行 */
        if (yStep < 1.0f)
            ;
        /* 大于等于1,移动plane行 */
        else
        {
            yStepInt = (int32_t)yStep;
            yStep -= yStepInt;
            plaPtr += plaLineSize * yStepInt;
        }
        imgPtr += imgLineSize;
    }
}

ImageGrid::ImageGrid(Image& image, int32_t divX, int32_t divY)
{
    shadow.Resize(image.Width(), image.Height(), image.Format(), image.Info().mem.addr);
    GridResize(divX, divY);
}

ImageGrid::ImageGrid(Image& image, int32_t x, int32_t y, int32_t width, int32_t height)
{
    shadow.Resize(image.Width(), image.Height(), image.Format(), image.Info().mem.addr);
    RangeSet(x, y, width, height);
}

ImageGrid::ImageGrid(ImageGrid& imageGrid, int32_t x, int32_t y, int32_t width, int32_t height)
{
    shadow = imageGrid.shadow;
    RangeSet(x + imageGrid.X(), y + imageGrid.Y(), width, height);
}

ImageGrid::ImageGrid()
{
    shadow.Resize(0, 0);
    RangeSet(0, 0, 0, 0);
}

ImageGrid::~ImageGrid()
{
    shadow.ForceSet(NULL);
}

int32_t ImageGrid::X() const
{
    return x;
}

int32_t ImageGrid::Y() const
{
    return y;
}

int32_t ImageGrid::Width() const
{
    return width;
}

int32_t ImageGrid::Height() const
{
    return height;
}

int32_t ImageGrid::Pb() const
{
    return shadow.Pb();
}

int32_t ImageGrid::Size() const
{
    return width * height * shadow.Pb();
}

ImageFormat ImageGrid::Format() const
{
    return shadow.Format();
}

ImageMem ImageGrid::Mem(int32_t x, int32_t y) const
{
    /* 范围检查 */
    x = x < 0 ? 0 : x % width;
    y = y < 0 ? 0 : y % height;
    ImageMem retMem = mem;
    if (retMem.addr)
        retMem.addr += (y * shadow.Width() + x) * shadow.Pb();
    return retMem;
}

ImageInfo ImageGrid::ShadowInfo() const
{
    return shadow.Info();
}

void ImageGrid::GridResize(int32_t divX, int32_t divY)
{
    this->divX = divX < 1 ? 1 : divX;
    this->divY = divY < 1 ? 1 : divY;
    width = shadow.Width() / this->divX;
    height = shadow.Height() / this->divY;
    index = 0;
    block = this->divX * this->divY;
    mem = shadow.Info().mem;
    /* 调整范围显示模式参数 */
    x = y = 0;
}

int32_t ImageGrid::GridIndex()
{
    return index;
}

void ImageGrid::GridSet(int32_t index)
{
    this->index = index % block;
    /* 转换为在原图像中的x,y坐标 */
    x = this->index % divX * width;
    y = this->index / divX * height;
    mem.addr = shadow.Info().mem.addr + (y * shadow.Width() + x) * shadow.Pb();
}

ImageMem ImageGrid::GridNext()
{
    GridSet(index + 1);
    return Mem();
}

void ImageGrid::RangeSet(int32_t x, int32_t y, int32_t width, int32_t height)
{
    /* 范围检查 */
    this->width = width < 0 ? 0 : (width < shadow.Width() ? width : shadow.Width());
    this->height = height < 0 ? 0 : (height < shadow.Height() ? height : shadow.Height());
    int32_t xEnd = x < 0 ? this->width : x + this->width;
    int32_t yEnd = y < 0 ? this->height : y + this->height;
    this->x = x < 0 ? 0 : (xEnd > shadow.Width() ? shadow.Width() - this->width : x);
    this->y = y < 0 ? 0 : (yEnd > shadow.Height() ? shadow.Height() - this->height : y);
    mem.addr = shadow.Info().mem.addr + (this->y * shadow.Width() + this->x) * shadow.Pb();
    /* 调整切块模式参数 */
    divX = divY = block = 1;
    index = 0;
}

ImageMem ImageGrid::RangeMove(int32_t x, int32_t y)
{
    RangeSet(this->x + x, this->y + y, width, height);
    return Mem();
}

Image* ImageGrid::ScreenShot()
{
    Image* retImg = new Image(width, height, shadow.Format());

    int32_t lineSize = width * shadow.Pb();
    ImageMem distMem = retImg->Mem();
    for (int32_t i = 0; i < height; i++)
    {
        memcpy(distMem.addr, Mem(0, i).addr, lineSize);
        distMem.addr += lineSize;
    }
    return retImg;
}

void ImageGrid::Clear(uint32_t color)
{
    shadow.Clear(color, x, y, width, height);
}

void ImageGrid::Clear(uint32_t color, int32_t x, int32_t y, int32_t width, int32_t height)
{
    shadow.Clear(color, this->x + x, this->y + y, width, height);
}

void ImageGrid::Write(int32_t x, int32_t y, uint32_t color)
{
    if (x < 0 || x >= width || y < 0 || y >= height)
        return;
    shadow.Write(this->x + x, this->y + y, color);
}

void ImageGrid::Write(int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
    if (x < 0 || x >= width || y < 0 || y >= height)
        return;
    shadow.Write(this->x + x, this->y + y, r, g, b, a);
}

void ImageGrid::Write(int32_t x, int32_t y, int32_t width, int32_t height, Image& plane)
{
    shadow.Write(this->x + x, this->y + y, width, height, plane);
}

void ImageGrid::Write(int32_t x, int32_t y, int32_t width, int32_t height, ImageGrid& plane)
{
    shadow.Write(this->x + x, this->y + y, width, height, plane);
}

void ImageGrid::Cover(int32_t x, int32_t y, uint32_t color)
{
    if (x < 0 || x >= width || y < 0 || y >= height)
        return;
    shadow.Cover(this->x + x, this->y + y, color);
}

void ImageGrid::Cover(int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
    shadow.Cover(this->x + x, this->y + y, r, g, b, a);
}

void ImageGrid::Cover(int32_t x, int32_t y, int32_t width, int32_t height, Image& plane)
{
    shadow.Cover(this->x + x, this->y + y, width, height, plane);
}

void ImageGrid::Cover(int32_t x, int32_t y, int32_t width, int32_t height, ImageGrid& plane)
{
    shadow.Cover(this->x + x, this->y + y, width, height, plane);
}
